package com.roin.learn.activiti.freemarker;

import freemarker.core.Environment;
import freemarker.template.*;
import org.springframework.stereotype.Component;

import java.io.IOException;
import java.io.Writer;
import java.util.Map;

/**
 * 自定义指令（标签）,把标签体的英文转成大写（小写），通过参数type来指定大小写，type如果不指定，则默认大写，但如果指定了，
 * 就能为upper或者lower
 * 例子：
 * 转成大写<@case type='upper'>mdadMIN</@case>，
 * 转成小写<@case type='lower'>mdadMIN</@case>
 */
@Component(value = "com.roin.learn.activiti.freemarker.CaseDirective")
public class CaseDirective implements TemplateDirectiveModel {
    private static final String TYPE = "type";

    public void execute(Environment env, Map map, TemplateModel[] templateModels,
                        TemplateDirectiveBody body) throws TemplateException, IOException {

        if (templateModels.length != 0) {
            throw new TemplateModelException("this directive doesn't allow variables");
        }
        String type = null;
        Object obj = map.get(TYPE);
        if (obj != null)
            type = obj.toString();
        if (body != null) {
            body.render(new CaseFilterWriter(env.getOut(), type));
        } else {
            throw new RuntimeException("missing body");
        }
    }


}

class CaseFilterWriter extends Writer {
    private static final String TYPE_UPPER = "upper";
    private static final String TYPE_LOWER = "lower";
    private final Writer out;
    private final String type;

    public CaseFilterWriter(Writer out, String type) {
        this.out = out;
        this.type = type;
    }

    @Override
    public void write(char[] cbuf, int off, int len) throws IOException {
        //默认转成大小
        if (type == null || TYPE_UPPER.equals(type))
            out.write(uppperCase(cbuf, off, len));
        else if (TYPE_LOWER.equals(type))
            out.write(lowerCase(cbuf, off, len));
        else
            throw new RuntimeException("Case can only be upper or lower, nor can it be filled！");
    }

    private char[] uppperCase(char[] cbuf, int off, int len) {
        char[] transformedCbuf = new char[len];
        for (int i = 0; i < len; i++) {
            transformedCbuf[i] = Character.toUpperCase(cbuf[i + off]);
        }
        return transformedCbuf;
    }

    private char[] lowerCase(char[] cbuf, int off, int len) {
        char[] transformedCbuf = new char[len];
        for (int i = 0; i < len; i++) {
            transformedCbuf[i] = Character.toLowerCase(cbuf[i + off]);
        }
        return transformedCbuf;
    }

    @Override
    public void flush() throws IOException {
        out.flush();
    }

    @Override
    public void close() throws IOException {
        out.close();

    }
}
